﻿#ifndef LK_SOUND_WAVE_
#define LK_SOUND_WAVE_
#ifdef _VC
#include<MMREG.H>
#endif
namespace LK
{
	namespace Sound
	{
		struct WaveFormat
		{
			// 格式信息
			double Hz;
			short Bits;
			short Channels;
			bool IsFloat;
			WaveFormat(double hz, short bits, short channels, bool isfloat = false) :Hz(hz), Bits(bits), Channels(channels), IsFloat(isfloat){}
#ifdef _WAVEFORMATEX_
			WaveFormat(WAVEFORMATEX x) :Hz(x.nSamplesPerSec), Bits(x.wBitsPerSample), Channels(x.nChannels), IsFloat(x.wFormatTag == 0xfffe){}
			operator WAVEFORMATEX()const
			{
				WAVEFORMATEX wfx;
				wfx.nSamplesPerSec = (DWORD)Hz;
				if (IsFloat)
				{
					wfx.wFormatTag = 0xfffe;
				}
				else wfx.wFormatTag = WAVE_FORMAT_PCM;
				wfx.wBitsPerSample = Bits;
				wfx.nChannels = Channels;
				wfx.nBlockAlign = Bits / 8 * Channels;
				wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
				wfx.cbSize = 0;
				return wfx;
			}
#endif
		};
		/**@brief 波形数据类，包含各种音频格式的数据*/
		struct WaveData :public Object
		{
		public:
			// 格式信息
			double Hz;
			short Bits;
			short Channels;
			bool IsFloat;
			// 音频数据
			Collection::PArray<u8> Data;
			/**@brief 默认构造无格式*/
			WaveData();
			/**@brief 获取音频格式*/
			WaveFormat GetFormat()const;
			/**@brief 设置音频格式*/
			void SetFormat(WaveFormat x)
			{
			    Hz=x.Hz;
			    Bits=x.Bits;
			    Channels=x.Channels;
			    IsFloat=x.IsFloat;
			}
			/**@brief 虚析构函数*/
			virtual ~WaveData(){}
			/**@brief 复制构造函数*/
			WaveData(const WaveData& x) :Hz(x.Hz), Bits(x.Bits), Channels(x.Channels), IsFloat(x.IsFloat), Data(x.Data->Clone()){}
			/**@brief 交换内容*/
			void SwapWith(WaveData& x){ Swap(Hz, x.Hz); Swap(Bits, x.Bits); Swap(Channels, x.Channels); Swap(IsFloat, x.IsFloat); Swap(Data,x.Data); }
			/**@brief 赋值*/
			WaveData& operator=(const WaveData& x){ SetFormat( x.GetFormat()); Data = x.Data; return *this; }
		};
		struct PWaveData : PObject
		{
		public:
			PMETHODS(PWaveData,WaveData)
			/**@brief 获取音频格式*/
			WaveFormat GetFormat()const{ return Ptr()->GetFormat(); }
			/**@brief 设置音频格式*/
			void SetFormat(WaveFormat f){ Ptr()->SetFormat(f); }
			/**@brief 获取音频数据*/
			Collection::PArray<u8>& GetData()const{ return Ptr()->Data; }
			/**@brief 设置音频数据*/
			void SetData(LK::Collection::PArray<u8>& x){ Ptr()->Data = x; }
			/**@brief 获取频率*/
			double GetHz()const{ return Ptr()->Hz; }
			/**@brief 设置频率*/
			void SetHz(double x){ Ptr()->Hz = x; }
			/**@brief 获取位数*/
			short GetBits()const{ return Ptr()->Bits; }
			/**@brief 设置位数*/
			void SetBits(short x){ Ptr()->Bits = x; }
			/**@brief 获取声道数*/
			short GetChannels()const{ return Ptr()->Channels; }
			/**@brief 设置声道数*/
			void SetChannels(short x){ Ptr()->Channels = x; }
			/**@brief 获取是否浮点*/
			bool GetIsFloat()const{ return Ptr()->IsFloat; }
			/**@brief 设置是否浮点*/
			void SetIsFloat(bool x){ Ptr()->IsFloat = x; }
		};
		/**@brief 波形类，处理音频格式的转换等*/
		struct Wave :public Object
		{
			// 声道数
			short Channels;
			// 位数
			short Bits;
			// 频率
			double Hz;
			// 浮点
			bool isFloat;
			// 缓冲区1
			LK::Collection::DefaultArray<u8> buffer;
			// 缓冲区2
			LK::Collection::DefaultArray<u8> buffer2;
			// 上次记录的音量值（每个声道一个值）
			double *lastValue;
			//上次记录的时间值
			double lastTime;
			// 时间值,Wati函数专用
			PTime time;
			/**@brief 将sourceData中的音频数据按toHz的频率和toBits的位数以及toFloat转换并返回*/
			Collection::PArray<u8> HzConvert(const void *sourceData, index_t length, double toHz, short toBits, bool toFloat = false);
			/**@brief 目标内存不能跟源内存重叠,声道转换不进行浮点和位数转换*/
			Collection::PArray<u8> ChConvert(const void *sourceData, index_t length, double hz, short bits, bool isfloat, short toChannels);
			Wave(const Wave&){}
			void operator=(const Wave&){}
		public:
			/**@brief 交换*/
			void SwapWith(Wave& x)
			{
				Swap(Channels, x.Channels);
				Swap(Bits, x.Bits);
				Swap(Hz, x.Hz);
				Swap(isFloat, isFloat);
				buffer.SwapWith(x.buffer);
				buffer2.SwapWith(x.buffer2);
				Swap(lastValue, x.lastValue);
				Swap(lastTime, x.lastTime);
				Swap(time, x.time);
			}
			Wave();
			~Wave();
			/**@brief 读写属性：音量*/
			double Volume;
			/**@brief 设置音频源格式*/
			void SetFormat(double hz, short bits, short channels, bool isfloat = false);
			/**@brief 设置音频源格式*/
			void SetFormat(const WaveFormat& wfx);
			/**@brief 设置默认音频源格式*/
			void SetFormat();
			/**@brief 转换音频格式*/
			template<typename T>Collection::PArray<T> Convert(const Collection::PArray<T>&sourceData, double toHz, short toBits, short toChannels, bool toFloat = false);
			/**@brief 转换音频格式*/
			template<typename T>Collection::PArray<T> Convert(const Collection::PArray<T>&sourceData, const WaveFormat& deswfx);
			/**@brief 取音频值*/
			static double GetValue(const void *buffer, short bits, size_t sampleIndex, bool isfloat = false);
			/**@brief 写入音频值*/
			static void SetValue(void *buffer, double value, short bits, size_t sampleIndex, bool isfloat = false);
			/**@brief 取音频值*/
			static double GetValue(const void *p, short bits, bool isfloat = false);
			/**@brief 写入音频值*/
			static void SetValue(void *p, double value, short bits, bool isfloat = false);
			/**@brief 生成WaveFormat音频格式*/
			static WaveFormat MakeFormat(double hz, short bits, short ch, bool isfloat = false);
			/**@brief 将pData2的音频叠加到pData1当中，bits为位数，count为单声道帧数*/
			template<typename T, typename AnyT>static void Mix(Collection::PArray<T>& pDest, const Collection::PArray<AnyT>& pData, double vol, short bits, bool isfloat = false);
			/**@brief 获取len字节的噪音，block的值为0~1的小数，指定网格化参数*/
			Collection::PArray<u8> GetNoise(size_t len, double block = 0);
			/**@brief 获取一个指定频率的波形*/
			Collection::PArray<u8> GetWaveWithSingleHz(double hz, size_t len, double block = 0);
			/**@brief 获取指定时间长度的噪音，block的值为0~1的小数，指定网格化参数*/
			PWaveData GetNoiseData(const PTime&t, double block = 0);
			/**@brief 获取指定时间长度的、指定频率的波形*/
			PWaveData GetWaveDataWithSingleHz(double hz, const PTime&t, double block = 0);
			/**@brief 等待由指定字节数表示的时间*/
			void Wait(size_t len);
		};
		struct PWave :public PObject
		{
		public:
			PMETHODS(PWave, Wave);
			/**@brief 获取音量*/
			double GetVolume()const{ return Ptr()->Volume; }
			/**@brief 设置音量*/
			void SetVolume(double vol){ Ptr()->Volume = vol; }
			/**@brief 设置音频源格式*/
			void SetFormat(double hz, short bits, short channels, bool isfloat = false){ return Ptr()->SetFormat(hz, bits, channels, isfloat); }
			/**@brief 设置音频源格式*/
			void SetFormat(const WaveFormat& wfx){ return Ptr()->SetFormat(wfx); }
			/**@brief 设置默认音频源格式*/
			void SetFormat(){ return Ptr()->SetFormat(); }
			/**@brief 转换音频格式*/
			template<typename T>Collection::PArray<T> Convert(const Collection::PArray<T>&sourceData, double toHz, short toBits, short toChannels, bool toFloat = false){ return Ptr()->Convert(sourceData, toHz, toBits, toChannels, toFloat); }
			/**@brief 转换音频格式*/
			template<typename T>Collection::PArray<T> Convert(const Collection::PArray<T>&sourceData, const WaveFormat& w){ return Ptr()->Convert(sourceData, w); }
			/**@brief 取音频值*/
			static inline double GetValue(const void *buffer, short bits, size_t sampleIndex, bool isfloat = false){ return Wave::GetValue(buffer, bits, sampleIndex, isfloat); }
			/**@brief 写入音频值*/
			static inline void SetValue(void *buffer, double value, short bits, size_t sampleIndex, bool isfloat = false){ return Wave::SetValue(buffer, value, bits, sampleIndex, isfloat); }
			/**@brief 取音频值*/
			static inline double GetValue(const void *p, short bits, bool isfloat = false){ return Wave::GetValue(p, bits, isfloat); }
			/**@brief 写入音频值*/
			static inline void SetValue(void *p, double value, short bits, bool isfloat = false){ return Wave::SetValue(p, value, bits, isfloat); }
			/**@brief 生成WaveFormat音频格式*/
			static inline WaveFormat MakeFormat(double hz, short bits, short ch, bool isfloat = false){ return Wave::MakeFormat(hz, bits, ch, isfloat); }
			/**@brief 将pData的音频叠加到pDest当中，bits为位数，count为单声道帧数*/
			template<typename T, typename AnyT>static inline void Mix(Collection::PArray<T>& pDest, const Collection::PArray<AnyT>& pData, double vol, short bits, bool isfloat = false){ return Wave::Mix(pDest, pData, vol, bits, isfloat); }
			/**@brief 获取len字节的噪音，block的值为0~1的小数，指定网格化参数*/
			Collection::PArray<u8> GetNoise(size_t len, double block = 0){ return Ptr()->GetNoise(len, block); }
			/**@brief 获取一个指定频率的波形*/
			Collection::PArray<u8> GetWaveWithSingleHz(double hz, size_t len, double block = 0){ return Ptr()->GetWaveWithSingleHz(hz, len, block); }
			/**@brief 获取指定时间长度的噪音，block的值为0~1的小数，指定网格化参数*/
			PWaveData GetNoiseData(const PTime&time, double block = 0){ return Ptr()->GetNoiseData(time, block); }
			/**@brief 获取指定时间长度的、指定频率的波形*/
			PWaveData GetWaveDataWithSingleHz(double hz, const PTime&time, double block = 0){ return Ptr()->GetWaveDataWithSingleHz(hz, time, block); }
			/**@brief 等待由指定字节数表示的时间*/
			void Wait(size_t len){ return Ptr()->Wait(len); }
		};


		template<typename T>Collection::PArray<T> Wave::Convert(const Collection::PArray<T>&sourceData, double toHz, short toBits, short toChannels, bool toFloat)
		{
			// 获得转换后的新内存和单声道帧数量
			Collection::PArray<u8> pdata = HzConvert((const T*)sourceData, sourceData.GetLengthOfBytes(), toHz, toBits, toFloat);
			// 转换声道数
			Collection::PArray<u8> pdata2 = ChConvert((unsigned char*)pdata, pdata.size(), toHz, toBits, toFloat, toChannels);
			// 返回一个引用
			return new Collection::ReferenceArray<T>((pdata2.size() / sizeof(T)), (T*)(unsigned char*)pdata2);
		}
		template<typename T>Collection::PArray<T> Wave::Convert(const Collection::PArray<T>&sourceData, const WaveFormat& deswfx)
		{
			return Convert(sourceData, deswfx.Hz, deswfx.Bits, deswfx.Channels, deswfx.IsFloat);
		}
		template<typename T, typename AnyT>void Wave::Mix(Collection::PArray<T>& pData1, const Collection::PArray<AnyT>& pData2, double vol, short bits, bool isfloat)
		{
			index_t tmp = pData1.GetLengthOfBytes() > pData2.GetLengthOfBytes() ? pData2.GetLengthOfBytes() : pData1.GetLengthOfBytes();
			tmp /= bits / 8;// 总帧数
			if (isfloat)// 32位才有浮点
			{
				float* pdes = (float*)(T*)pData1;
				float* pend = pdes + tmp;
				float* pstart = (float*)const_cast<AnyT*>((const AnyT*)pData2);
				while (pdes < pend)
				{
					*pdes += float(*pstart * vol);
					++pdes;
					++pstart;
				}
				return;
			}
			if (bits == 32)
			{
				index_t* pdes = (index_t*)(T*)pData1;
				index_t* pend = pdes + tmp;
				index_t* pstart = (index_t*)const_cast<AnyT*>((const AnyT*)pData2);
				while (pdes < pend)
				{
					*pdes += index_t(*pstart * vol);
					++pdes;
					++pstart;
				}
				return;
			}
			if (bits == 16)
			{
				short* pdes = (short*)(T*)pData1;
				short* pend = pdes + tmp;
				short* pstart = (short*)const_cast<AnyT*>((const AnyT*)pData2);
				while (pdes < pend)
				{
					*pdes += short(*pstart * vol);
					++pdes;
					++pstart;
				}
				return;
			}
			unsigned char* pdes = (unsigned char*)(T*)pData1;
			unsigned char* pend = pdes + tmp;
			unsigned char* pstart = (unsigned char*)const_cast<AnyT*>((const AnyT*)pData2);
			while (pdes < pend)
			{
				*pdes = *pdes - 128 + (unsigned char)((index_t(*pstart) - 128) * vol + 128);
				++pdes;
				++pstart;
			}
			return;
		}

	}
}
#endif
